package cn.lwj.webService.util;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.springframework.util.Assert;

public class ReflectUtils<M extends Serializable, E extends Serializable> {

	private static Logger log = Logger.getLogger("cn.net.withub.common.utils.ReflectUtils");
	 
	    private void ReflectionUtils() {
	    }
	 
	    /**
	     * 直接读取对象属性值,无视private/protected修饰符,不经过getter函数.
	     */
	    public static Object getFieldValue(final Object object, final String fieldName) {
	        Field field = getDeclaredField(object, fieldName);
	 
	        if (field == null)
	            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
	 
	        makeAccessible(field);
	 
	        Object result = null;
	        try {
	            result = field.get(object);
	        } catch (IllegalAccessException e) {
	        	log.info("不可能抛出的异常{}"+e.getMessage() );
	        }
	        return result;
	    }
	 
	    /**
	     * 直接设置对象属性值,无视private/protected修饰符,不经过setter函数.
	     */
	    public static void setFieldValue(final Object object, final String fieldName, final Object value) {
	        Field field = getDeclaredField(object, fieldName);
	 
	        if (field == null)
	            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
	 
	        makeAccessible(field);
	 
	        try {
	            field.set(object, value);
	        } catch (IllegalAccessException e) {
	        	log.info("不可能抛出的异常:{}"+e.getMessage());
	        }
	    }
	 
	    /**
	     * 循环向上转型,获取对象的DeclaredField.
	     */
	    public static Field getDeclaredField(final Object object, final String fieldName) {
	        Assert.notNull(object, "object不能为空");
	        return getDeclaredField(object.getClass(), fieldName);
	    }
	 
	    /**
	     * 循环向上转型,获取类的DeclaredField.
	     */
	    @SuppressWarnings("unchecked")
	    public static Field getDeclaredField(final Class clazz, final String fieldName) {
	        Assert.notNull(clazz, "clazz不能为空");
	        Assert.hasText(fieldName, "fieldName");
	        for (Class superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
	            try {
	                return superClass.getDeclaredField(fieldName);
	            } catch (NoSuchFieldException e) {
	                // Field不在当前类定义,继续向上转型
	            }
	        }
	        return null;
	    }
	 
	    /**
	     * 强制转换fileld可访问.
	     */
	    public static void makeAccessible(final Field field) {
	        if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {
	            field.setAccessible(true);
	        }
	    }
	 
	    /**
	     * 通过反射,获得定义Class时声明的父类的泛型参数的类型. 如public UserDao extends HibernateDao<User>
	     * 
	     * @param clazz
	     *            The class to introspect
	     * @return the first generic declaration, or Object.class if cannot be
	     *         determined
	     */
	    @SuppressWarnings("unchecked")
	    public static Class getSuperClassGenricType(final Class clazz) {
	        return getSuperClassGenricType(clazz, 0);
	    }
	 
	    /**
	     * 通过反射,获得定义Class时声明的父类的泛型参数的类型. 如public UserDao extends
	     * HibernateDao<User,Long>
	     * 
	     * @param clazz
	     *            clazz The class to introspect
	     * @param index
	     *            the Index of the generic ddeclaration,start from 0.
	     * @return the index generic declaration, or Object.class if cannot be
	     *         determined
	     */
	 
	    @SuppressWarnings("unchecked")
	    public static Class getSuperClassGenricType(final Class clazz, final int index) {
	 
	        Type genType = clazz.getGenericSuperclass();
	 
	        if (!(genType instanceof ParameterizedType)) {
	            log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
	            return Object.class;
	        }
	 
	        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
	 
	        if (index >= params.length || index < 0) {
	        	log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length);
	            return Object.class;
	        }
	        if (!(params[index] instanceof Class)) {
	        	log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
	            return Object.class;
	        }
	        return (Class) params[index];
	    }
	 
	    /**
	     * 提取集合中的对象的属性,组合成List.
	     * 
	     * @param collection
	     *            来源集合.
	     * @param
	     *
	     */
	    @SuppressWarnings("unchecked")
	    public static List fetchElementPropertyToList(final Collection collection, final String propertyName) throws Exception {
	 
	        List list = new ArrayList();
	 
	        for (Object obj : collection) {
	            list.add(PropertyUtils.getProperty(obj, propertyName));
	        }
	 
	        return list;
	    }
	 

	    
	    /*************************************************************************************************************************************************/
	    
	    /**
		 * 通过构造函数实例化对象 
		 * @param className       类的全路径名称	
		 * @param parameterTypes  参数类型
		 * @param initargs        参数值
		 * @return
		 */
		@SuppressWarnings("rawtypes")
		public static Object constructorNewInstance(String className,Class [] parameterTypes,Object[] initargs) { 
			try {
				Constructor<?> constructor = (Constructor<?>) Class
						.forName(className).getDeclaredConstructor(parameterTypes);					    //暴力反射
				constructor.setAccessible(true);
				return constructor.newInstance(initargs);
			} catch (Exception ex) {
				throw new RuntimeException();
			}

		}

		
		/**
		 * 暴力反射获取字段值
		 * @param obj       实例对象
		 * @return          属性值
		 */
		public static Object getFieldValue(String propertyName, Object obj) {
			try {
				Field field = obj.getClass().getDeclaredField(propertyName);			
				field.setAccessible(true);
				return field.get(obj);
			} catch (Exception ex) {
				throw new RuntimeException();
			}
		}

		/**
		 * 暴力反射获取字段值
		 * @param propertyName 属性名
		 * @param object       实例对象
		 * @return          字段值
		 */
		public static Object getProperty(String propertyName, Object object) {
			try {
				
				PropertyDescriptor pd = new PropertyDescriptor(propertyName,object.getClass());
				Method method = pd.getReadMethod();
				return method.invoke(object);
				
				//其它方式
				/*BeanInfo beanInfo =  Introspector.getBeanInfo(object.getClass());
				PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
				Object retVal = null;
				for(PropertyDescriptor pd : pds){
					if(pd.getName().equals(propertyName))
					{
						Method methodGetX = pd.getReadMethod();
						retVal = methodGetX.invoke(object);
						break;
					}
				}
				return retVal;*/
			} catch (Exception ex) {
				throw new RuntimeException();
			}
		}
		
		/**
		 * 通过BeanUtils工具包获取反射获取字段值,注意此值是以字符串形式存在的,它支持属性连缀操作:如,.对象.属性
		 * @param propertyName 属性名
		 * @param object       实例对象
		 * @return          字段值
		 */
		public static Object getBeanInfoProperty(String propertyName, Object object) {
			try {			
				return BeanUtils.getProperty(object, propertyName);
			} catch (Exception ex) {
				throw new RuntimeException();
			}
		}
		
		/**
		 * 通过BeanUtils工具包获取反射获取字段值,注意此值是以字符串形式存在的
		 * @param object       实例对象
		 * @param propertyName 属性名
		 * @param value        字段值
		 * @return          
		 */
		public static void setBeanInfoProperty(Object object,String propertyName,String value) {
			try {			
				BeanUtils.setProperty(object, propertyName,value);
			} catch (Exception ex) {
				throw new RuntimeException();
			}
		}
		
		/**
		 * 通过BeanUtils工具包获取反射获取字段值,注意此值是以对象属性的实际类型
		 * @param propertyName 属性名
		 * @param object       实例对象
		 * @return          字段值
		 */
		public static Object getPropertyUtilByName(String propertyName, Object object) {
			try {			
				return PropertyUtils.getProperty(object, propertyName);
			} catch (Exception ex) {
				throw new RuntimeException();
			}
		}
		
		/**
		 * 通过BeanUtils工具包获取反射获取字段值,注意此值是以对象属性的实际类型,这是PropertyUtils与BeanUtils的根本区别
		 * @param object       实例对象
		 * @param propertyName 属性名
		 * @param value        字段值
		 * @return          
		 */
		public static void setPropertyUtilByName(Object object,String propertyName,Object value) {
			try {			
				PropertyUtils.setProperty(object, propertyName,value);
			} catch (Exception ex) {
				throw new RuntimeException();
			}
		}
		
		/**
		 * 设置字段值	
		 * @param propertyName 属性名
		 * @param value        新的字段值
		 * @return          
		 */
		public static void setProperties(Object object, String propertyName,Object value) throws IntrospectionException,
				IllegalAccessException, InvocationTargetException {
			PropertyDescriptor pd = new PropertyDescriptor(propertyName,object.getClass());
			Method methodSet = pd.getWriteMethod();
			methodSet.invoke(object,value);
		}
		
		
		/**
		 * 设置字段值
		 * @param propertyName 字段名
		 * @param obj          实例对象
		 * @param value        新的字段值
		 * @return          
		 */
		public static void setPropertyValue(Object obj,String propertyName,Object value) {
			try {
				Field field = obj.getClass().getDeclaredField(propertyName);		
				field.setAccessible(true);
				field.set(obj, value);
			} catch (Exception ex) {
				throw new RuntimeException();
			}
		}
		
		/**
		 * 设置字段值
		 * @param className        类的全路径名称
		 * @param methodName       调用方法名
		 * @param parameterTypes   参数类型
		 * @param values           参数值
		 * @param object           实例对象
		 * @return          
		 */
		@SuppressWarnings("rawtypes")
		public static Object methodInvoke(String className,String methodName,Class [] parameterTypes,Object [] values,Object object) {
			try {
				Method method = Class.forName(className).getDeclaredMethod(methodName,parameterTypes);
				method.setAccessible(true);
				return method.invoke(object,values);
			} catch (Exception ex) {
				throw new RuntimeException();
			}
		}
		
		/** 
	     * 提供两种bean之间的值拷贝  M：值提供者，E:值接受者 
	     * getBeanList 
	     * @param modelList 
	     * @return  
	     * List<E> 
	     * @exception  
	     * @since  1.0.0 
	     */  
	    public List<E> getBeanList(List<M> modelList) {  
	        List<E> entityList = new ArrayList<E>();  
	        if(modelList!=null){  
	            for(M model : modelList) {  
	                entityList.add(getBean(model));  
	            }  
	        }  
	        return entityList;  
	    }  
	      
	    /** 
	     * 提供两种bean之间的值拷贝  M：值提供者，E:值接受者 
	     * getBean 
	     * @param model 
	     * @return  
	     * E 
	     * @exception  
	     * @since  1.0.0 
	     */  
	    @SuppressWarnings("unchecked")  
	    public E getBean(M model) {  
	        // 通过反射获取注解“E”（即模型对象）的类型，  
	        // 这里必须要有子类继承才能获取，否则会报java.lang.Class cannot be cast to java.lang.reflect.ParameteriedType  
	        // 索引0为第一个泛型M，索引1为第二个泛型E，依次类推  
	        Class<E> entityClass = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];  
	        E entity = null;  
	        try {  
	            entity = (E) entityClass.newInstance();  
	        } catch (InstantiationException e) {  
	            e.printStackTrace();  
	        } catch (IllegalAccessException e) {  
	            e.printStackTrace();  
	        }  
	        if(model==null){  
	            return null;  
	        }else{  
//	            BeanUtils.copyProperties(model, entity);  
	        }  
	        return entity;  
	    }
	    
	    /** 
	     * 提供两种bean之间的值拷贝  M：值提供者，E:值接受者 
	     * getBean 
	     * @return
	     * E 
	     * @exception  
	     * @since  1.0.0 
	     */  
	    @SuppressWarnings("unchecked")  
	    public E getNewInstanceObject(Class<?> claz) {  
	        // 通过反射获取注解“E”（即模型对象）的类型，  
	        // 这里必须要有子类继承才能获取，否则会报java.lang.Class cannot be cast to java.lang.reflect.ParameteriedType  
	        // 索引0为第一个泛型M，索引1为第二个泛型E，依次类推  
	        Class<E> entityClass = (Class<E>) ((ParameterizedType) claz.getGenericSuperclass()).getActualTypeArguments()[1];  
	        E entity = null;  
	        try {  
	            entity = (E) entityClass.newInstance();  
	        } catch (InstantiationException e) {  
	            e.printStackTrace();  
	        } catch (IllegalAccessException e) {  
	            e.printStackTrace();  
	        }  
	        
	        return entity;  
	    }
	
}
